package com.tianji.learning.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.ILearningRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2024-11-06
 */
@SuppressWarnings("ALL")
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final LearningRecordMapper recordMapper;

    /**
     * 2、分页查询我的课表
     * @param pageQuery 分页查询参数对象（Day2 - 课堂2）
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> pageQueryMyLessons(PageQuery pageQuery) {
        // 1、获取当前登录人
        Long userId = UserContext.getUser();

        // 2、发起分页查询
        Page<LearningLesson> page  = lambdaQuery().eq(LearningLesson::getUserId, userId)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }
        // 3.查询课程信息
        Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);

        List<LearningLessonVO> list = new ArrayList<>(records.size());
        for (LearningLesson r : records) {
            LearningLessonVO v = BeanUtils.toBean(r, LearningLessonVO.class);
            list.add(v);
            // 3.1.设置课程信息
            CourseSimpleInfoDTO cInfo = cMap.get(r.getCourseId());
            v.setCourseName(cInfo.getName());
            v.setCourseCoverUrl(cInfo.getCoverUrl());
            v.setSections(cInfo.getSectionNum());
            list.add(v);
        }

        return PageDTO.of(page, list);
    }

    @Override
    @Transactional
    public void addUserLessons(Long userId, List<Long> courseIds) {

        // 1.查询课程有效期
        List<CourseSimpleInfoDTO> cInfoList  = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(cInfoList)) {
            // 课程不存在，无法添加
            log.error("课程信息不存在，无法添加到课表");
            return;
        }
        // 2.循环遍历，处理LearningLesson数据
        List<LearningLesson> list = new ArrayList<>(cInfoList.size());
        for (CourseSimpleInfoDTO cInfo : cInfoList) {
            LearningLesson lesson = new LearningLesson();
            // 2.1.获取过期时间
            Integer validDuration = cInfo.getValidDuration();
            if (validDuration != null && validDuration > 0) {
                LocalDateTime now = LocalDateTime.now();
                lesson.setCreateTime(now);
                lesson.setExpireTime(now.plusMonths(validDuration));
            }
            // 2.2.填充userId和courseId
            lesson.setUserId(userId);
            lesson.setCourseId(cInfo.getId());
            list.add(lesson);
        }
        // 3.批量新增
        saveBatch(list);
    }

    @Override
    public LearningLessonVO queryMyCurrentLesson() {
        Long userId = UserContext.getUser();
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (lesson == null) {
            return null;

        }
        LearningLessonVO v = BeanUtils.toBean(lesson, LearningLessonVO.class);
        // 3.1.查询课程信息
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false,false);
        if (cInfo == null) {
            // 课程不存在，无法添加
            throw new BadRequestException("课程信息不存在！");
        }
        v.setCourseName(cInfo.getName());
        v.setCourseCoverUrl(cInfo.getCoverUrl());
        v.setSections(cInfo.getSectionNum());
        // 5.统计课表中的课程数量 select count(1) from xxx where user_id = #{userId}
        Integer count = lambdaQuery().eq(LearningLesson::getUserId, userId).count();
        v.setCourseAmount(count);
        // 6.查询小节信息
        List<CataSimpleInfoDTO> cataInfos =
                catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
        if (!CollUtils.isEmpty(cataInfos)) {
            CataSimpleInfoDTO cataInfo = cataInfos.get(0);
            v.setLatestSectionName(cataInfo.getName());
            v.setLatestSectionIndex(cataInfo.getCIndex());
        }
        return v;

    }

    @Override
    public LearningLessonVO queryLessonByCourseId(Long courseId) {
        Long userId = UserContext.getUser();
        if (userId != null){
            return null;
        }
        // 1.查询课程信息
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        if (lesson == null) {
            return null;
        }
        // 3.处理VO
        return BeanUtils.copyBean(lesson, LearningLessonVO.class);
    }

    @Override
    public void deleteCourseFromLesson(Long userId, Long courseId) {
        // 1.获取当前登录用户
        if (userId == null) {
            userId = UserContext.getUser();
        }
        // 2.删除课程
        remove(buildUserIdAndCourseIdWrapper(userId, courseId));
    }

    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        return lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .in(LearningLesson::getStatus,
                        LessonStatus.NOT_BEGIN.getValue(),
                        LessonStatus.LEARNING.getValue(),
                        LessonStatus.FINISHED.getValue())
                .count();
    }

    @Override
    public Long isLessonValid(Long courseId) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        if (userId == null) {
            return null;
        }
        // 2.查询课程
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        if (lesson == null || LessonStatus.EXPIRED.equals(lesson.getStatus())) {
            return null;
        }
        return lesson.getId();
    }

    @Override
    public void createPlans(LearningPlanDTO planDTO) {
        //1.查询课程信息
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(UserContext.getUser(), planDTO.getCourseId()));

        //2.更新信息计划数据
        this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq, planDTO.getFreq())
                .set(lesson.getPlanStatus().equals(PlanStatus.NO_PLAN),LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .eq(LearningLesson::getId, lesson.getId())
                .update();

       /* this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq, planDTO.getFreq())
                .set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .eq(LearningLesson::getCourseId, planDTO.getCourseId())
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .update();*/
    }

    @Override
    public LearningPlanPageVO queryMyPlansPage(PageQuery pageQuery) {
        LearningPlanPageVO vo = new LearningPlanPageVO();
        //1.获取用户
        Long userId = UserContext.getUser();
        //2.分页查询我的课表（创建过学习计划、状态：未学习、学习中，倒序）
        Page<LearningLesson> pageResult = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = pageResult.getRecords();
        if (ObjectUtils.isEmpty(records)){
            return vo.emtyPage(pageResult);
        }
        //3.查询课程填充数据(根据课程id集合查询课程信息）
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = queryCourseSimpleInfoList(records);

        //4.统计学习记录表中 本周学习小结数据
        LocalDateTime begin= DateUtils.getWeekBeginTime(LocalDate.now());
        LocalDateTime end= DateUtils.getWeekEndTime(LocalDate.now());
        QueryWrapper<LearningRecord> queryWrapper=new QueryWrapper<>();
        queryWrapper.select("lesson_id as id,cound(1) as num")
                .eq("user_id", userId)
                .eq("finished",true)
                .between("finish_time",begin,end)
                .groupBy("lesson_id");


        List<Map<String, Object>> mapList = recordMapper.selectMaps(queryWrapper);
        Map<Long, Long> learnedSectionNumMap = mapList.stream()
                .collect(Collectors.toMap(map -> (Long) map.get("id"), map -> (Long) map.get("num")));

        //5。循环之前查询的分页课表数据，填充课程信息
        List<LearningPlanVO> voList = new ArrayList<>(records.size());
        for (LearningLesson record : records) {
            //5.1.拷贝po至vo
            LearningPlanVO learningPlanVO = BeanUtils.copyBean(record, LearningPlanVO.class);
            //5.2.填充课程信息
            CourseSimpleInfoDTO couseInfo = courseInfoMap.get(record.getCourseId());
            if (ObjectUtil.isNotEmpty(couseInfo)){
                learningPlanVO.setCourseName(couseInfo.getName());
                learningPlanVO.setSections(couseInfo.getSectionNum());
            }

            // 5.3.填充本周学习小结数据
            learningPlanVO.setWeekLearnedSections(learnedSectionNumMap.getOrDefault(record.getId(),0L).intValue());
            //5.4.添加到VO集合中
            voList.add(learningPlanVO);
        }

        //6.计算本周计划学习总小结数
        LearningLesson lesson = this.query()
                .select("sum(week_freq) as total_weekfreq")
                .eq("user_id", userId)
                .eq("plan_status", PlanStatus.PLAN_RUNNING)
                .in("status", LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .one();

        //7.计算本周已学习小结数
        long sum = learnedSectionNumMap.values().stream().mapToLong(num -> num.longValue()).sum();
        Integer weekFinished = Long.valueOf(sum).intValue();

        //learnedSectionNumMap.values().stream().flatMapToLong(num -> LongStream.of(num).sum());
        //Long sum2 = learnedSectionNumMap.values().stream().map(Function,identity()).reduce(Long::sum).get();

        //8.封装VO返回
        vo.setWeekTotalPlan(lesson.getTotalWeekfreq());
        vo.setWeekFinished(weekFinished);
        vo.setWeekPoints(null);
        return vo.pageInfo(pageResult.getTotal(), pageResult.getPages(), voList);
    }

    private Wrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
        LambdaQueryWrapper<LearningLesson> queryWrapper = new QueryWrapper<LearningLesson>()
                .lambda()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId);
        return queryWrapper;
    }


    private Map<Long, CourseSimpleInfoDTO> queryCourseSimpleInfoList(List<LearningLesson> records) {
        // 3.1.获取课程id
        Set<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        // 3.2.查询课程信息
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIds);
        if (CollUtils.isEmpty(cInfoList)) {
            // 课程不存在，无法添加
            throw new BadRequestException("课程信息不存在！");
        }
        // 3.3.把课程集合处理成Map，key是courseId，值是course本身
        Map<Long, CourseSimpleInfoDTO> cMap = cInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        return cMap;
    }
}
